package postgresql

import (
	"database/sql"
	"fmt"
	"go_auto/project/init_project"
	"log"
	"sync"
	"time"

	_ "github.com/lib/pq"
)

var (
	dbConn     *sql.DB
	dbOnce     sync.Once
	dbLastPing time.Time // 最后一次ping的时间，用于重连机制
)

const reconnectInterval = 5 * time.Second // 重连间隔时间

// GetDB 获取数据库连接
func GetDBPool() *sql.DB {
	dbOnce.Do(func() {
		postgreSqlinfo := init_project.ProjectConfig.Get("postgresql")
		var psqlInfo string
		if postgreSqlinfo != nil {
			psqlInfo = fmt.Sprintf(
				"host=%s port=%.0f user=%s password=%s dbname=%s sslmode=disable",
				postgreSqlinfo.(map[string]interface{})["postgresql_host"],
				postgreSqlinfo.(map[string]interface{})["postgresql_port"],
				postgreSqlinfo.(map[string]interface{})["postgresql_user"],
				postgreSqlinfo.(map[string]interface{})["postgresql_password"],
				postgreSqlinfo.(map[string]interface{})["postgresql_dbname"],
			)
		}

		dbConn, err := sql.Open("postgres", psqlInfo)
		if err != nil {
			log.Fatal(err)
		}

		dbConn.SetMaxIdleConns(5)                       // 最大闲置连接数
		dbConn.SetMaxOpenConns(20)                      // 最大连接数
		dbConn.SetConnMaxLifetime(30 * time.Second)     // 连接最长使用时间
		dbConn.SetConnMaxIdleTime(10 * time.Second)     // 连接最长闲置时间
		dbConn.Ping()                                   // 预连接
		dbLastPing = time.Now().Add(-reconnectInterval) // 设置最后一次ping的时间
	})

	// 检查最后一次ping的时间，如果超过reconnectInterval则重新连接
	if time.Since(dbLastPing) > reconnectInterval {
		err := dbConn.Ping()
		if err != nil {
			log.Printf("Failed to reconnect to PostgreSql: %v", err)
			return nil
		}
		dbLastPing = time.Now()
	}

	return dbConn
}

// 查询方法
func PoolQuerySql(db *sql.DB, sqlStatement string) []map[string]string {

	rows, err := db.Query(sqlStatement)
	if err != nil {
		panic(err)
	}
	defer rows.Close()
	//列出所有查询结果的字段名
	cols, _ := rows.Columns()

	//values是每个列的值，这里获取到byte里
	values := make([][]byte, len(cols))

	//query.scan的参数，因为每次查询出来的列是不定长的，用len(cols)定住当次查询的长度
	scans := make([]interface{}, len(cols))

	//让每一行数据都填充到[][]byte里面
	for i := range values {
		scans[i] = &values[i]
	}
	res := make([]map[string]string, 0)
	for rows.Next() {
		_ = rows.Scan(scans...)
		row := make(map[string]string)
		for k, v := range values { //每行数据是放在values里面，现在把它挪到row里
			key := cols[k]
			row[key] = string(v)
		}
		res = append(res, row)
	}
	fmt.Printf("数据查询：%s:%s", sqlStatement, res)
	return res
}

// ExecSql 执行sql语句
func PoolExecSql(db *sql.DB, sqlStatement string, sqlParameter_swap []string) {
	var sqlParameter []interface{}
	for _, value := range sqlParameter_swap {
		sqlParameter = append(sqlParameter, value)
	}

	stmt, err := db.Prepare(sqlStatement)
	if err != nil {
		panic(err)
	}

	res, err := stmt.Exec(sqlParameter...)
	if err != nil {
		panic(err)
	}

	fmt.Printf("res = %d", res)
}
